/* 
 *  Copyright (C) 2006 James Young
 * `gurumind(a)gmail.com
 * 
 */

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Collections;
using System.Drawing;

namespace IPDEditor
{
    public enum IPDUIType { TreeView, ListView, VisualView };

    public abstract class IPDUIElement
    {
        protected static Format format = new Format();

        //public shared field type consts. sort by database name alphabet

        //Service Book
        protected const byte fldtypeGatewayIPAddr = 16;
        protected const byte fldtypeAPN = 18;
        protected const byte fldtypeGateWayPort = 20;

        //shared members
        protected IPDItem _ipdItem;

        public IPDUIElement()
        { }

        public IPDUIElement(IPDItem IpdItem)
        {
            _ipdItem = IpdItem;
        }

        public virtual void Update()
        {
            //data changed. will update UI
        }

        public virtual TreeNode CreateTreeNode()
        {
            return null;
        }

        public virtual void CreateListView(ListView listView)
        {
            listView.Items.Clear();
        }

        public virtual void CreateVisualView(Panel panel)
        {
            panel.Controls.Clear();
            IPDEditorBase editor = new IPDEditorBase();
            editor.Dock = DockStyle.Fill;
            panel.Tag = null;
            panel.Controls.Add(editor);
        }

        public virtual void FillData(IPDItem IpdItem)
        {
        }

        protected void InitListViewColums(ListView listView, List<colDesc> colList)
        {
            //create struct
            listView.Columns.Clear();
            ColumnHeader ch0 = new ColumnHeader();
            ch0.Text = "";
            ch0.Width = 15;
            listView.Columns.Add(ch0);
                        
            foreach (colDesc cd in colList)
            {                
                ColumnHeader ch1 = new ColumnHeader();
                ch1.Width = cd.colWidth;
                ch1.Text = cd.colName;
                listView.Columns.Add(ch1);
            }
        }

        public virtual bool visEdit
        {
            get
            {
                return false;
            }
        }
        public virtual bool visAdd
        {
            get
            {
                return false;
            }
        }

        public virtual string ToShortString()
        {
            return "";
        }

        protected virtual string Field2String(IPDField field)
        {
            return "";
        }
    }

    public struct colDesc
    {
        public string colName;
        public int colWidth;
        public colDesc(string ColumnName)
        {
            colName = ColumnName;
            colWidth = 60;
        }
        public colDesc(string ColumnName, int ColumnWidth)
        {
            colName = ColumnName;
            colWidth = ColumnWidth;
        }
    }

    public class IPDUIFile : IPDUIElement
    {
        IPDFile _ipdFile;
        TreeNode _tnBind;

        public IPDUIFile(IPDFile IpdFile)
        {
            _ipdFile = IpdFile;
        }

        public IPDFile ipdFile
        {
            get
            {
                return _ipdFile;
            }
        }

        public override void Update()
        {
            _tnBind.Text = _ipdFile.FileNameShort;
        }

        public override TreeNode CreateTreeNode()
        {
            _tnBind = new TreeNode(_ipdFile.FileNameShort);
            _tnBind.Tag = this;

            IPDDocument doc = _ipdFile.document;
            for (int i = 0; i < doc.Items.Count; i++)
            {
                IPDUIName uiname = new IPDUIName(doc.Items[i]);
                _tnBind.Nodes.Add(uiname.CreateTreeNode());
            }

            return _tnBind;
        }

        public override void CreateListView(ListView listView)
        {
            listView.Items.Clear();

            if (!(listView.Tag is IPDUIFile))
            {
                List<colDesc> cols = new List<colDesc>();
                cols.Add(new colDesc("Content List", 500));
                InitListViewColums(listView, cols);
            }

            for(int i = 0; i < _ipdFile.document.Items.Count; i++)
            {
                ListViewItem lvi = new ListViewItem();
                lvi.SubItems.Add(_ipdFile.document.Items[i].name);
                lvi.SubItems.Add(i.ToString());

                lvi.Tag = new IPDUIName(_ipdFile.document.Items[i]);
                listView.Items.Add(lvi);
            }

            listView.Tag = this;
        }

        public void Changed(bool changed)
        {
            if (_tnBind == null)
                return;

            if (changed)
            {
                if (_tnBind.Text.IndexOf("*") < 0)
                    _tnBind.Text += "*";
            }
            else
                _tnBind.Text = _tnBind.Text.Replace("*", "");
        }
    }

    public class IPDUIName : IPDUIElement
    {
        TreeNode _tn;
        new IPDName _ipdItem;

        public IPDUIName(IPDName IpdName)
        {
            _ipdItem = IpdName;
        }

        public IPDName ipdName
        {
            get
            {
                return _ipdItem;
            }
        }

        public TreeNode Add(IPDDatabase record)
        {
            _ipdItem.Items.Add(record);
            IPDVisualRecord vrec = new IPDVisualRecord(record);
            TreeNode tnTmp = vrec.CreateTreeNode();
            _tn.Nodes.Add(tnTmp);
            
            _tn.TreeView.SelectedNode = tnTmp;
            return tnTmp;
        }

        public void Remove(IPDDatabase record)
        {
            for (int i = 0; i < _ipdItem.Items.Count; i++)
            {
                if (_ipdItem[i].uid.Equals(record.uid))
                {
                    foreach (TreeNode tn in _tn.Nodes)
                    {
                        IPDVisualRecord vr = (IPDVisualRecord)tn.Tag;
                        if (vr.record.uid.Equals(record.uid))
                        {
                            _tn.Nodes.Remove(tn);
                            break;
                        }
                    }
                    _ipdItem.Items.Remove(record);
                    break;
                }
                    
            }
            _ipdItem.Items.Remove(record);
        }

        public override TreeNode CreateTreeNode()
        {
            _tn = new TreeNode(_ipdItem.name);
            _tn.Tag = this;


            for (int i = 0; i < _ipdItem.Items.Count; i++)
            {
                IPDVisualRecord rec = new IPDVisualRecord(_ipdItem.Items[i]);
                _tn.Nodes.Add(rec.CreateTreeNode());
            }

            return _tn;
        }

        public override void CreateListView(ListView listView)
        {
            listView.Items.Clear();
            if (!(listView.Tag is IPDUIName))
            {
                List<colDesc> cols = new List<colDesc>();
                cols.Add(new colDesc("ID"));
                cols.Add(new colDesc("Version"));
                cols.Add(new colDesc("Offset"));
                cols.Add(new colDesc("Length"));
                cols.Add(new colDesc("Handle"));
                cols.Add(new colDesc("UID", 75));
                cols.Add(new colDesc("Content Description", 300));
                InitListViewColums(listView, cols);
            }

            for (int i = 0; i < _ipdItem.Items.Count; i++)
            {
                ListViewItem lvi = new ListViewItem();
                lvi.SubItems.Add(_ipdItem[i].dbId.ToString());
                lvi.SubItems.Add(_ipdItem[i].dbver.ToString());
                lvi.SubItems.Add(_ipdItem[i].offset.ToString());
                lvi.SubItems.Add(_ipdItem[i].length.ToString());
                lvi.SubItems.Add(_ipdItem[i].recHandle.ToString());
                lvi.SubItems.Add(EncUtil.BIN2HexString(_ipdItem[i].uid));
                lvi.SubItems.Add(_ipdItem[i].ToLongString());

                lvi.Tag = new IPDVisualRecord(_ipdItem[i]);
                listView.Items.Add(lvi);
            }
            listView.Tag = this;
        }
    }

    public class IPDVisualRecord : IPDUIElement
    {
        TreeNode _tn;
        ListView _lv;
        protected new IPDDatabase _ipdItem;

        public IPDVisualRecord(IPDDatabase IpdDatabase)
        {
            _ipdItem = IpdDatabase;
        }

        public override bool visEdit
        {
            get
            {
                return true;
            }
        }
        public override bool visAdd
        {
            get
            {
                return true;
            }
        }

        public override TreeNode CreateTreeNode()
        {
            _tn = new TreeNode(_ipdItem.ToString());
            _tn.Tag = this;

            if (_ipdItem is IPDServiceBook)
            {
                foreach (IPDField field in _ipdItem.Items)
                {
                    IPDUIField uiField = new IPDUIField(field);
                    TreeNode tnField = uiField.CreateTreeNode();
                    _tn.Nodes.Add(tnField);

                    if (field is IPDFieldHRT)
                    {
                        foreach (IPDField sf in field.subFields)
                        {
                            IPDUIField uiSubField = new IPDUIField(sf);
                            tnField.Nodes.Add(uiSubField.CreateTreeNode());
                        }
                    }
                }
            }

            return _tn;
        }

        public TreeNode AppendBrother(IPDDatabase record)
        {
            IPDUIName nm = (IPDUIName)_tn.Parent.Tag;
            return nm.Add(record);
        }

        public void RemoveBrother(IPDDatabase record)
        {
            IPDUIName nm = (IPDUIName)_tn.Parent.Tag;
            nm.Remove(record);            
        }

        public override void Update()
        {
            _tn.Text = _ipdItem.ToString();
            CreateListView(_lv);
        }

        public override void CreateListView(ListView listView)
        {
            _lv = listView;
            listView.Items.Clear();

            string recKey = string.Format(fmtrecord.format, _ipdItem.Parent.name, _ipdItem.dbver);
            if (format.records.ContainsKey(recKey))
            {
                List<colDesc> cols = new List<colDesc>();
                cols.Add(new colDesc("Name", 100));
                cols.Add(new colDesc("Content", 400));
                InitListViewColums(listView, cols);

                foreach (fmtfield fld in format.records[recKey].fields)
                {
                    List<IPDField> flds = _ipdItem.GetTypeOf(fld.type);
                    if (flds.Count > 0 && fld.index < flds.Count)
                    {
                        ListViewItem lvi = new ListViewItem();
                        lvi.SubItems.Add(fld.name);

                        lvi.SubItems.Add(fld.ReadBinary(flds[fld.index].data));
                        listView.Items.Add(lvi);
                    }
                }
            }
            else
            {
//                if (!(listView.Tag is IPDDatabase))
//                {
                    List<colDesc> cols = new List<colDesc>();
                    cols.Add(new colDesc("Offset"));
                    cols.Add(new colDesc("Length"));
                    cols.Add(new colDesc("Type"));
                    cols.Add(new colDesc("Is Unicode"));
                    cols.Add(new colDesc("Field Data", 300));
                    InitListViewColums(listView, cols);
//                }
                for (int i = 0; i < _ipdItem.Items.Count; i++)
                {
                    ListViewItem lvi = new ListViewItem();
                    lvi.SubItems.Add(_ipdItem[i].offset.ToString());
                    lvi.SubItems.Add(_ipdItem[i].len.ToString());
                    lvi.SubItems.Add(_ipdItem[i].type.ToString());
                    lvi.SubItems.Add(_ipdItem[i].IsUnicode.ToString());
                    lvi.SubItems.Add(Field2String(_ipdItem[i]));

                    lvi.Tag = new IPDUIField(_ipdItem[i]);
                    listView.Items.Add(lvi);
                }
            }
            listView.Tag = this;
        }

        public override void CreateVisualView(Panel panel)
        {
            switch (_ipdItem.Parent.name)
            {
                //case "AutoText":
                //    if (!(panel.Tag is IPDEditorAutoText))
                //    {
                //        panel.Controls.Clear();
                //        IPDEditorAutoText eat = new IPDEditorAutoText();                        
                //        eat.Dock = DockStyle.Fill;
                //        panel.Controls.Add(eat);
                //        panel.Tag = eat;                        
                //    }
                //    IPDEditorAutoText editor = (IPDEditorAutoText)panel.Tag;
                //    editor.visualRecord = this;
                //    editor.FillData(_ipdItem);
                //    break;
                case "Service Book":
                    if (!(panel.Tag is IPDEditorServiceBook))
                    {
                        panel.Controls.Clear();
                        IPDEditorServiceBook esb = new IPDEditorServiceBook();
                        esb.Dock = DockStyle.Fill;
                        panel.Controls.Add(esb);
                        panel.Tag = esb;
                    }
                    IPDEditorServiceBook edsb = (IPDEditorServiceBook)panel.Tag;
                    edsb.visualRecord = this;
                    edsb.FillData(_ipdItem);
                    break;
                default:
                    base.CreateVisualView(panel);
                    break;
            }
        }

        public IPDDatabase record
        {
            get
            {
                return _ipdItem;
            }
        }

        protected override string Field2String(IPDField field)
        {
            return EncUtil.AutoBin2String(field.data);
        }

        protected void AddTextEdit(Control control, ContentEdit ceControl, object tag, DataUpdator updator, string txtName, string txtValue)
        {
            ceControl.lblName.Text = txtName + ":";
            ceControl.txtBox.Text = txtValue;
            ceControl.Location = new Point(0, 26 * control.Controls.Count);
            ceControl.Anchor |= AnchorStyles.Right;
            ceControl.txtBox.Tag = tag;
            ceControl.txtBox.TextChanged += new EventHandler(updator);
            control.Controls.Add(ceControl);
        }

        protected void AddSelectionEdit(Control control, SelectionEdit seControl, object tag, DataUpdator updator, string txtName, Hashtable htValues, object defautValue)
        {
            foreach (string s in htValues.Keys)
            {
                seControl.AddRadio(s, htValues[s], htValues[s].Equals(defautValue), new EventHandler(updator));
            }

            seControl.lblName.Text = txtName + ":";
            seControl.Location = new Point(0, 26 * control.Controls.Count);
            seControl.Anchor |= AnchorStyles.Right;
            seControl.lblName.Tag = tag;
            control.Controls.Add(seControl);
        }

        protected void AddVisualBanner(Control control, string bannerText)
        {
            VisualBanner vb = new VisualBanner();
            vb.lblBanner.Text = bannerText;
            vb.Location = new Point(0, 26 * control.Controls.Count);
            vb.Anchor |= AnchorStyles.Right;

            //button events
            vb.btnAddNew.Click += new EventHandler(btnAddNew_Click);
            vb.btnDelete.Click += new EventHandler(btnDelete_Click);
            vb.btnSave.Click += new EventHandler(btnSave_Click);
            control.Controls.Add(vb);
        }

        void btnSave_Click(object sender, EventArgs e)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        void btnDelete_Click(object sender, EventArgs e)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        void btnAddNew_Click(object sender, EventArgs e)
        {
            //Visualize(
        }

        protected virtual IPDVisualRecord CreateNew()
        {
            return this;
        }

        public void Visualize(Control control, VisualizerType visType)
        {
            //control.Controls.Clear();
            //IPDName nm = (IPDName)parent;

            //if (visType == VisualizerType.Adding)
            //{
            //    AddVisualBanner(control, "Add new record of " + nm.name);
            //    Visualize(control, CreateNew());
            //}
            //else
            //{
            //    AddVisualBanner(control, "Edit record of " + nm.name);
            //    Visualize(control, this);
            //}            
        }

        protected virtual void Visualize(Control control, IPDVisualRecord record)
        { 
            
        }

        private void TextBoxFieldUpdator(object sender, EventArgs e)
        {
            TextBox tb = (TextBox)sender;
            ContentEdit ce = tb.Parent as ContentEdit;
            IPDField fld = tb.Tag as IPDField;
            try
            {
                if (ChangeField(fld, tb.Text))
                {
                    ce.ep1.Clear();
                    //fld.Changed = true;
                }
                else
                    throw new Exception("Update not supported or UFO come to earth.");
            }
            catch (Exception ex)
            {
                ce.ep1.SetError(tb, ex.ToString());
            }
        }

        private void SelectionFieldUpdator(object sender, EventArgs e)
        {
            //RadioButton rb = (RadioButton)sender;
            //SelectionEdit se = rb.Parent.Parent as SelectionEdit;
            //IPDField fld = se.lblName.Tag as IPDField;
            //try
            //{
            //    if (rb.Checked)
            //    {
            //        if (CheckField(fld, rb.Tag))
            //        {
            //            se.ep1.Clear();
            //            //fld.Changed = true;
            //        }
            //        else
            //            throw new Exception("Update not supported or UFO come to earth.");
            //    }
            //}
            //catch (Exception ex)
            //{
            //    se.ep1.SetError(rb.Parent, ex.ToString());
            //}
        }

        public virtual bool UpdateFieldAsNumber(IPDField fld, object tag)
        {
            if (tag is int)
            {
                int d = (int)tag;
                fld.data[0] = (byte)(d & 0x000000FF);
                fld.data[1] = (byte)((d & 0x0000FF00) >> 8);
                fld.data[2] = (byte)((d & 0x00FF0000) >> 16);
                fld.data[3] = (byte)((d & 0xFF000000) >> 24);
            }
            else if (tag is short)
            {
                short d = (short)tag;
                fld.data[0] = (byte)(d & 0xFF);
                fld.data[1] = (byte)((d & 0xFF00) >> 8);
            }
            else if (tag is byte)
            {
                byte d = (byte)tag;
                fld.data[0] = d;
            }
            else
                return false;
            return true;
        }

        protected virtual bool ChangeField(IPDField fld, string inputText)
        {
            return UpdateFieldAsMixString(fld, inputText);
        }

        protected bool UpdateFieldAsAscii(IPDField fld, string inputText)
        {
            byte[] tmpBuff = Encoding.ASCII.GetBytes(inputText);
            fld.data = tmpBuff;
            fld.len = (short)fld.data.Length;

            return true;
        }

        protected virtual bool UpdateFieldAsMixString(IPDField fld, string inputText)
        {
            return UpdateFieldAsMixString(fld, inputText, Encoding.UTF8);
        }

        public bool UpdateFieldAsMixString(IPDField fld, string inputText, Encoding enc)
        {
            fld.data = EncUtil.AutoString2Bin(inputText, enc, false);
            fld.len = (short)fld.data.Length;

            return true;
        }

        protected void AddRadioSelectionEdit(Control control, object tag, string txtName, Hashtable ht, object defaultValue)
        {
            AddSelectionEdit(control, new SelectionEdit(), tag, new DataUpdator(SelectionFieldUpdator), txtName, ht, defaultValue);
        }

        protected void AddTextBoxEdit(Control control, object tag, string txtName, string txtValue)
        {
            AddTextEdit(control, new ContentEdit(), tag, new DataUpdator(TextBoxFieldUpdator), txtName, txtValue);
        }

        protected void AddTextBoxEdit(Control control, ContentEdit ceControl, object tag, string txtName, string txtValue)
        {
            AddTextEdit(control, ceControl, tag, new DataUpdator(TextBoxFieldUpdator), txtName, txtValue);
        }
    }

    public class IPDUIField : IPDUIElement
    {
        new IPDField _ipdItem;
        TreeNode _tn;
        ListView _lv;

        public IPDUIField(IPDField IpdField)
        {
            _ipdItem = IpdField;
        }

        public override TreeNode CreateTreeNode()
        {
            _tn = new TreeNode(_ipdItem.ToString());
            _tn.Tag = this;
            return _tn;
        }

        public override void CreateListView(ListView listView)
        {
            _lv = listView;
            listView.Items.Clear();
            if (!(listView.Tag is IPDUIField))
            {
                List<colDesc> cols = new List<colDesc>();
                cols.Add(new colDesc("Offset"));
                cols.Add(new colDesc("Length"));
                cols.Add(new colDesc("Type"));
                cols.Add(new colDesc("Is Unicode"));
                cols.Add(new colDesc("Field Data", 300));
                InitListViewColums(listView, cols);
            }

            if (_ipdItem.subFields != null)
            {
                foreach (IPDField subFld in _ipdItem.subFields)
                {
                    ListViewItem subLvi = new ListViewItem();
                    subLvi.SubItems.Add(subFld.offset.ToString());
                    subLvi.SubItems.Add(subFld.len.ToString());
                    subLvi.SubItems.Add(subFld.type.ToString());
                    subLvi.SubItems.Add(subFld.IsUnicode.ToString());
                    subLvi.SubItems.Add(subFld.ToString());
                    subLvi.Tag = new IPDUIField(subFld);
                    listView.Items.Add(subLvi);
                }
            }
            else
            {
                ListViewItem lvi = new ListViewItem();
                lvi.SubItems.Add(_ipdItem.offset.ToString());
                lvi.SubItems.Add(_ipdItem.len.ToString());
                lvi.SubItems.Add(_ipdItem.type.ToString());
                lvi.SubItems.Add(_ipdItem.IsUnicode.ToString());
                lvi.SubItems.Add(_ipdItem.ToString());
                lvi.Tag = new IPDUIField(_ipdItem);
                listView.Items.Add(lvi);
            }
            
            listView.Tag = this;
        }

        public override void CreateVisualView(Panel panel)
        {
            if (_ipdItem is IPDFieldHRT)
            {
                if (!(panel.Tag is HRTEditor))
                {
                    panel.Controls.Clear();
                    HRTEditor eat = new HRTEditor();
                    eat.Dock = DockStyle.Fill;
                    panel.Controls.Add(eat);
                    panel.Tag = eat;
                }
                HRTEditor editor = (HRTEditor)panel.Tag;
                editor.ipdUIHRT = this;
                editor.FillData(_ipdItem);
            }
            else if(_ipdItem is IPDFieldSBAppData)
            {
                //generic editor goes here
                if(!(panel.Tag is IPDEditorGeneric))
                {
                    panel.Controls.Clear();
                    IPDEditorGeneric gene = new IPDEditorGeneric();
                    gene.Dock = DockStyle.Fill;
                    panel.Controls.Add(gene);
                    panel.Tag = gene;
                }
                IPDEditorGeneric editor = (IPDEditorGeneric)panel.Tag;
                editor.ipdUIField = this;
                editor.FillData(_ipdItem);
            }
            else
            {
                panel.Controls.Clear();
                panel.Tag = null;
            }
        }

        public IPDField field
        {
            get
            {
                return _ipdItem;
            }
        }
    }

}
